home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / apml / part01 next >
Encoding:
Internet Message Format  |  1989-02-03  |  25.3 KB

  1. Path: xanth!mcnc!gatech!ukma!cwjcc!hal!ncoast!allbery
  2. From: ljz@fxgrp.UUCP (Lloyd Zusman)
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i113: Arbitrary Precision Math Library -- 1 of 5
  5. Message-ID: <8810051944.AA05696@fxgrp.fx.com>
  6. Date: 7 Oct 88 00:09:31 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: ljz@fxgrp.UUCP (Lloyd Zusman)
  9. Lines: 640
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 4, Issue 113
  13. Submitted-by: "Lloyd Zusman" <ljz@fxgrp.UUCP>
  14. Archive-name: apml/Part1
  15.  
  16. Enclosed you will find the Arbitrary Precision Math Library (1 of 5)
  17.  
  18. Please post this to the comp.sources.misc newsgroup.
  19.  
  20. I finally got this into good enough shape to send out to the net. To use,
  21. just unshar the 5 pieces, read the README file, possibly alter the makefiles
  22. to conform to your system's conventions, and then type 'make test'.
  23.  
  24. Good luck!
  25.  
  26. --
  27.   Lloyd Zusman                  Internet:  ljz@fx.com
  28.   Master Byte Software                  or ljz%fx.com@ames.arc.nasa.gov
  29.   Los Gatos, California                 or fxgrp!ljz@ames.arc.nasa.gov
  30.   "We take things well in hand."    uucp:  ...!ames!fxgrp!ljz
  31.   [ our Internet connection is down: use uucp or mail to the entry above it ]
  32.  
  33. #--------------------------Cut Here--------------------------
  34. #! /bin/sh
  35. # This is a shell archive.  Remove anything before the "#! /bin/sh" line,
  36. # then unpack it by saving it in a file and typing "sh file."
  37. #
  38. # Wrapped by Lloyd Zusman (ljz) at fxgrp on Wed Oct  5 12:41:51 1988
  39. #
  40. # unpacks with default permissions
  41. #
  42. # Contents : README FUNCTIONS
  43. #
  44. if `test ! -s README`
  45. then
  46. echo "x - README"
  47. sed 's/^X//' > README << '@\END_OF_FILE_README'
  48. X
  49. X                Arbitrary Precision Math Library
  50. X
  51. XThe Arbitrary Precision Math Library is a series of routines that
  52. Xallows the user to perform math to any level of accuracy that is
  53. Xdesired.  These APM entities ("APM" == "Arbitrary Precision Math") can
  54. Xbe initialized from character strings or from long integers, and they
  55. Xcan be converted back into character strings by a routine that allows
  56. Xsimple formatting.  With the exception of the routines that do
  57. Xdivision, the results of APM operations are guaranteed to contain
  58. Xenough precision to hold exact values.  The APM routines will
  59. Xautomatically allocate enough space in their results to hold the
  60. Xproper number of digits.
  61. X
  62. XThe APM math is done on a new data type called "APM".  This is
  63. Xactually a pointer to a structure, but the contents of the structure
  64. Xshould never be manipulated: all operations on APM entities are done
  65. Xthrough a functional interface.
  66. X
  67. XAPM items can be represented in any of 36 bases: 2 through 36 and
  68. X10000.  The latter is quite useful: numbers that are represented in
  69. Xbases that are powers of 10 are quite easy to accurately convert to
  70. Xand from character strings containing their decimal representation,
  71. Xand 10000 is the largest power of 10 that fits into a short integer
  72. X(16 bits).  The base must fit into a short integer since calculations
  73. Xinternal to the APM routines need up to twice as much storage as is
  74. Xneeded to hold the base, and the largest unit we can deal with easily
  75. Xis a long integer (2 shorts).  It turns out that speed improves and
  76. Xmemory usage decreases as the magnitude of the base increases, so base
  77. X10000 is a win in both counts.  I have done some informal benchmarks
  78. Xin which base 10000 is 6 to 10 times faster than base 10 for numbers
  79. Xwith 15 - 20 decimal digits of precision.
  80. X
  81. XAlthough there is a multitude of bases, there is as yet no provision
  82. Xfor conversion from one base to another, except for the special case
  83. Xof converting between base-10 character strings and base-10000 APM
  84. Xvalues.  All the input APM parameters to any given APM routine must be
  85. Xof the same base.
  86. X
  87. XThe caller must initialize all APM values before the routines can
  88. Xoperate on them (including the values intended to contain results of
  89. Xcalculations).  Once this initialization is done, the user never needs
  90. Xto worry about resizing the APM values, as this is handled inside the
  91. XAPM routines and is totally invisible to the user.
  92. X
  93. XThe result of a APM operation cannot be one of the other APM operands.
  94. XIf you want this to be the case, you must put the result into a
  95. Xtemporary variable and then assign it to the appropriate operand.
  96. X
  97. XAll of the routines set the value of a global integer called
  98. X"apm_errno" to an error status: 0 means the operation succeeded, > 0
  99. Xmeans there was a warning but that there still is a result, and < 0
  100. Xmeans there was an error which prohibited the operation from
  101. Xcompleting.  Except where otherwise noted, the routines return this
  102. Xsame status value.
  103. X
  104. XThe caller has the option of registering a handler for errors and
  105. Xwarnings.  If this has been done, the handler will be invoked as each
  106. XAPM routine returns, and it will be passed appropriate information as
  107. Xto the status of the call to this APM routine.  With a registered
  108. Xerror handler it is not necessary for the caller to check the error
  109. Xcode after each call to a APM routine.
  110. X
  111. XFor ease of debugging, each APM routine is actually a macro that saves
  112. Xthe file name and line number and then calls a function of a slightly
  113. Xdifferent name.  This allows the error handler to report the exact
  114. Xlocation of the APM operation which caused the error.  The macros you
  115. Xwill use have names of the form "apmRoutineName".  To get the
  116. Xcorresponding actual function name (say, when using a debugger),
  117. Xreplace all capital letters with an underbar ("_") followed by its
  118. Xlower-case counterpart.  For example, for a hypothetical routine
  119. Xcalled "apmRoutineName", the actual function will be named
  120. X"apm_routine_name".  You should never explicitly call the actual
  121. Xfunction.
  122. X
  123. XYou should avoid using symbols that start with the characters "APM_"
  124. Xand "apm_", as they may clash with symbols that already exist in the
  125. XAPM Library.
  126. X
  127. XThere is one routine for each basic arithmetic operation such as
  128. Xadding, subtracting, etc.  This can become cumbersome when the result
  129. Xof a complicated expression is desired.  Therefore, I have added a
  130. Xroutine that will perform a series of operations in the manner of an
  131. XRPN ("Reverse Polish Notation") calculator.  See the routine 'apmCalc'
  132. X(below) for more details.
  133. X
  134. XIn my original version of this library, I discovered that a great deal
  135. Xof system overhead was wasted allocating and deallocating APM values.
  136. XSo, I adopted what has turned out to be a noticibly faster allocation
  137. Xscheme: newly allocated APM values are stored in a list.  When the
  138. Xuser disposes of one of these, it isn't really freed: its entry in the
  139. Xlist is marked as unused.  Subsequent attempts to allocate a new APM
  140. Xvalue will make use of any existing entries in this list that are
  141. Xmarked as unused instead of allocating a new entry.  Only when there
  142. Xare no unused entries in the list will a new entry be allocated.
  143. XThere is a routine that can be called which will perform a garbage
  144. Xcollection: i.e., it actually frees all unused APM entries (see
  145. X'apmGarbageCollect', below).
  146. X
  147. XA file called apm.h must be included in all programs that use the APM
  148. Xroutines.  It defines the "APM" data type, the error codes, the
  149. Xapm_errno variable, and several other things.
  150. X
  151. XThis software was written in as portable a manner as possible.  I have
  152. Xgotten it running successfully under several environments: on a Sun
  153. X3/xxx using SunOS 3.5 and 4.0, on an IBM RT running under AIX, under
  154. XMSDOS on an IBM PC using Microsoft C version 5.1 and Turbo C version
  155. X1.5 (or was it version 2.0?).  There are two makefiles: the one called
  156. X"Makefile" is the unix version ... it works under SunOS 3.5 and I
  157. Xpresume it would be easy to alter it to work under other unix
  158. Xenvironments; the one called "makefile.msc" will build the library
  159. Xunder MSDOS using Microsoft C version 5.1 ... it is meant to run with
  160. Xthe make program "PC/MAKE".
  161. X
  162. XI'm sure that some of you will find ways of enhancing and speeding up
  163. Xthe routines in this library.  Time permitting, I will be doing that
  164. Xas well.  I urge you to post your bug fixes and changes to the net and
  165. Xmail them to me at my address below, so they might be incorporated
  166. Xinto a later version of this library.  Some suggested areas of
  167. Xenhancement and optimization are:
  168. X
  169. X1)    Somehow speeding up the memory allocation scheme.
  170. X
  171. X2)    Some sort of floating-point/APM conversion.  I left this out
  172. X    because of the widely varying floating-point formats that
  173. X    exist on the various machines these routines can and might run
  174. X    on, and because I intended APM to *replace* floating-point,
  175. X    not to work in conjunction with it.
  176. X
  177. X3)    Base conversion.
  178. X
  179. X4)    Roots, powers, logarithms, trig functions, exponential functions,
  180. X    etc.
  181. X
  182. X5)      More productions in the makefiles ("install", "rdist", etc.).
  183. X
  184. X6)      A fancy installation script.
  185. X
  186. X7)    Writing a man page for all this.
  187. @\END_OF_FILE_README
  188. else
  189.   echo "shar: Will not over write README"
  190. fi
  191. if `test ! -s FUNCTIONS`
  192. then
  193. echo "x - FUNCTIONS"
  194. sed 's/^X//' > FUNCTIONS << '@\END_OF_FILE_FUNCTIONS'
  195. XAPM
  196. XapmInit(init, scale_factor, base)
  197. Xlong init;
  198. Xint scale_factor;
  199. Xshort base;
  200. X{}
  201. X  This routine initializes a new APM value.  The 'init' parameter is a long
  202. X  integer that represents its initial value, the 'scale_factor' variable
  203. X  indicates how this initial value should be scaled, and 'base' is the base of
  204. X  the initial value.  Note that the APM value returned by this routine is
  205. X  normally a reclaimed APM value that has been previously disposed of via
  206. X  apmDispose(); only if there are no previous values to be reclaimed will this
  207. X  routine allocate a fresh APM value (see also the apmGarbageCollect()
  208. X  routine).
  209. X
  210. X  Bases can be 2 - 36, 10000, or 0, where 0 defaults to base 10000.
  211. X
  212. X  If the call fails, it will return (APM)NULL and 'apm_errno' will contain a
  213. X  meaningful result.  Otherwise, a new APM value will be initialized.
  214. X
  215. X  For example, assume that we want to initialize two APM values in base 10000,
  216. X  the first to 1.23456 and the second to 1 E20 ("one times 10 to the 20th
  217. X  power"):
  218. X
  219. X      APM apm_1 = apmInit(123456L, -5, 0);
  220. X      APM apm_2 = apmInit(1L, 20, 0);
  221. X
  222. X  As a convenience, the following macro is defined in apm.h:
  223. X
  224. X      #define apmNew(BASE)    apmInit(0L, 0, (BASE))
  225. X
  226. Xint
  227. XapmDispose(apm)
  228. XAPM apm;
  229. X{}
  230. X  This routine disposes of a APM value 'apm' by returning it to the list of
  231. X  unused APM values (see also the apmGarbageCollect() routine).  It returns
  232. X  an appropriate status which is also put into 'apm_errno'.
  233. X
  234. Xint
  235. XapmGarbageCollect()
  236. X{}
  237. X  When APM values are disposed of, they remain allocated.  Subsequent calls to
  238. X  apmInit() may then return a previously allocated but disposed APM value.
  239. X  This is done for speed considerations, but after a while there may be lots of
  240. X  these unused APM values lying around.  This routine reclaims the space taken
  241. X  up by these unused APM values (it frees them).  It returns an appropriate
  242. X  status which is also put into 'apm_errno'.
  243. X
  244. Xint
  245. XapmAdd(result, apm1, apm2)
  246. XAPM result;
  247. XAPM apm1;
  248. XAPM apm2;
  249. X{}
  250. X  This routine adds 'apm1' and 'apm2', putting the sum into 'result', whose
  251. X  previous value is destroyed.  Note that all three parameters must have been
  252. X  previously initialized via apmInit().
  253. X
  254. X  The 'result' parameter cannot be one of the other APM parameters.
  255. X
  256. X  The return code and the 'apm_error' variable reflect the status of this
  257. X  function.
  258. X
  259. Xint
  260. XapmSubtract(result, apm1, apm2)
  261. XAPM result;
  262. XAPM apm1;
  263. XAPM apm2;
  264. X{}
  265. X  This routine subtracts 'apm2' from 'apm1', putting the difference into
  266. X  'result', whose previous value is destroyed.  Note that all three parameters
  267. X  must have been previously initialized via apmInit().
  268. X
  269. X  The 'result' parameter cannot be one of the other APM parameters.
  270. X
  271. X  The return code and the 'apm_errno' variable reflect the status of this
  272. X  function.
  273. X
  274. Xint
  275. XapmMultiply(result, apm1, apm2)
  276. XAPM result;
  277. XAPM apm1;
  278. XAPM apm2;
  279. X{}
  280. X  This routine multiplies 'apm1' and 'apm2', putting the product into 'result',
  281. X  whose previous value is destroyed.  Note that all three parameters must have
  282. X  been previously initialized via apmInit().
  283. X
  284. X  The 'result' parameter cannot be one of the other APM parameters.
  285. X
  286. X  The return code and the 'apm_errno' variable reflect the status of this
  287. X  function.
  288. X
  289. Xint
  290. XapmDivide(quotient, radix_places, remainder, apm1, apm2)
  291. XAPM quotient;
  292. Xint radix_places;
  293. XAPM remainder;
  294. XAPM apm1;
  295. XAPM apm2;
  296. X{}
  297. X  This routine divides 'apm1' by 'apm2', producing the 'quotient' and
  298. X  'remainder' variables.  Unlike the other three basic operations,
  299. X  division cannot be counted on to produce non-repeating decimals, so
  300. X  the 'radix_places' variable exists to tell this routine how many
  301. X  digits to the right of the radix point are to be calculated before
  302. X  stopping.  If the 'remainder' variable is set to (APM)NULL, no
  303. X  remainder is calculated ... this saves quite a bit of computation time
  304. X  and hence is recommended whenever possible.
  305. X
  306. X  All APM values must have been previously initialized via apmInit() (except,
  307. X  of course the 'remainder' value if it is to be set to NULL).
  308. X
  309. X  Division by zero creates a zero result and a warning.
  310. X
  311. X  The 'quotient' and 'remainder' variables can't be one of the other APM
  312. X  parameters.
  313. X
  314. X  The return code and the 'apm_errno' variable reflect the status of this
  315. X  function.
  316. X
  317. Xint
  318. XapmCompare(apm1, apm2)
  319. XAPM apm1;
  320. XAPM apm2;
  321. X{}
  322. X  This routine compares 'apm1' and 'apm2', returning -1 if 'apm1' is less than
  323. X  'apm2', 1 if 'apm1' is greater than 'apm2', and 0 if they are equal.
  324. X
  325. X  It is not an error if 'apm1' and 'apm2' are identical, and in this case the
  326. X  return value is 0.
  327. X
  328. X  The 'apm_errno' variable contains the error code.  You must check this value:
  329. X  if it is set to an error indication, the comparison failed and the return
  330. X  value is therefore meaningless.
  331. X
  332. Xint
  333. XapmCompareLong(apm, longval, scale_factor, base)
  334. XAPM apm;
  335. Xlong longval;
  336. Xint scale_factor;
  337. Xshort base;
  338. X{}
  339. X  This routine works just like apmCompare(), but it compares the 'apm' value to
  340. X  'longval', scaled by 'scale_factor' in 'base'.  The 'apm_errno' variable
  341. X  contains the error code.
  342. X
  343. Xint
  344. XapmSign(apm)
  345. XAPM apm;
  346. X{}
  347. X  This routine returns the sign of the 'apm' value: -1 for negative, 1 for
  348. X  positive.  The 'apm_errno' variable contains the error code.  You must check
  349. X  'apm_errno': if it's non-zero, the function return value is meaningless.
  350. X
  351. Xint
  352. XapmAbsoluteValue(result, apm)
  353. XAPM result;
  354. XAPM apm;
  355. X{}
  356. X  This routine puts the absolute value of 'apm' into 'result', whose previous
  357. X  value is destroyed.  Note that the two parameters must have been previously
  358. X  initialized via apmInit().
  359. X
  360. X  The 'result' parameter cannot be the other APM parameter.
  361. X
  362. X  The return code and the 'apm_errno' variable reflect the status of this
  363. X  function.
  364. X
  365. Xint
  366. XapmNegate(result, apm)
  367. XAPM result;
  368. XAPM num;
  369. X{}
  370. X  This routine puts the additive inverse of 'apm' into 'result', whose previous
  371. X  value is destroyed.  Note that the two parameters must have been previously
  372. X  initialized via apmInit().
  373. X
  374. X  The 'result' parameter cannot be the other APM parameter.
  375. X
  376. X  The return code and the 'apm_errno' variable reflect the status of this
  377. X  function.
  378. X
  379. Xint
  380. XapmReciprocal(result, radix_places, apm)
  381. XAPM result;
  382. Xint radix_places;
  383. XAPM num;
  384. X{}
  385. X  This routine puts the multiplicative inverse of 'apm' into 'result', whose
  386. X  previous value is destroyed.  Note that the two APM parameters must have been
  387. X  previously initialized via apmInit().  Since taking the reciprocal involves
  388. X  doing a division, the 'radix_places' parameter is needed here for the same
  389. X  reason it's needed in the apmDivide() routine.
  390. X
  391. X  Taking the reciprocal of zero yields zero with a warning status.
  392. X
  393. X  The 'result' parameter cannot be the other APM parameter.
  394. X
  395. X  The return code and the 'apm_errno' variable reflect the status of this
  396. X  function.
  397. X
  398. Xint
  399. XapmScale(result, apm, scale_factor)
  400. XAPM result;
  401. XAPM apm;
  402. Xint scale_factor;
  403. X{}
  404. X  This routine assigns to 'result' the value of 'apm' with its radix point
  405. X  shifted by 'scale_factor' (positive 'scale_factor' means shift left).  The
  406. X  'scale_factor' represents how many places the radix is shifted in the base of
  407. X  'apm' unless 'apm' is in base 10000 ...  in this special case, 'scale_factor'
  408. X  is treated as if the base were 10.
  409. X
  410. X  This is a very quick and accurate way to multiply or divide by a power of 10
  411. X  (or the number's base).
  412. X
  413. X  The 'result' parameter cannot be the other APM parameter.
  414. X
  415. X  The return code and the 'apm_errno' variable reflect the status of this
  416. X  function.
  417. X
  418. Xint
  419. XapmValidate(apm)
  420. XAPM apm;
  421. X{}
  422. X  This routine sets 'apm_errno' and its return status to some non-zero value if
  423. X  'apm' is not a valid APM value.
  424. X
  425. Xint
  426. XapmAssign(result, apm)
  427. XAPM result;
  428. XAPM num;
  429. X{}
  430. X  This routine assigns the value of 'apm' to 'result', whose previous value is
  431. X  destroyed.  Note that the two parameters must have been previously
  432. X  initialized via apmInit().
  433. X
  434. X  It is not considered an error if 'result' and 'apm' are identical; this case
  435. X  is a virtual no-op.
  436. X
  437. X  The return code and the 'apm_errno' variable reflect the status of this
  438. X  function.
  439. X
  440. Xint
  441. XapmAssignLong(result, long_value, scale_factor, base)
  442. XAPM result;
  443. Xlong long_value;
  444. Xint scale_factor;
  445. Xshort base;
  446. X{}
  447. X  This routine assigns a long int to 'result'.  Its second through fourth
  448. X  parameters correspond exactly to the parameters of apmInit().  The only
  449. X  difference between the two routines is that this one requires that its result
  450. X  be previously initialized.  The 'long_value' parameter is a long that
  451. X  represents the value to assign to 'result', the 'scale_factor' variable
  452. X  indicates how this value should be scaled, and 'base' is the base of the
  453. X  value.
  454. X
  455. X  Bases can be 2 - 36, 10000, or 0, where 0 defaults to base 10000.
  456. X
  457. X  For example, assume that we want to assign values to two previously
  458. X  initialized APM entities, apm_1 and apm_2.  The base will be base 10000, the
  459. X  first value will be set to 1.23456 and the second will be set to 1 E20 ("one
  460. X  times 10 to the 20th power"):
  461. X
  462. X      int ercode;
  463. X
  464. X      ercode = apmAssignLong(apm_1, 123456L, -5, 0);
  465. X      ...
  466. X
  467. X      ercode = apmAssignLong(apm_2, 1L, 20, 0);
  468. X      ...
  469. X
  470. X  The return code and the 'apm_errno' variable reflect the status of this
  471. X  function.
  472. X
  473. Xint
  474. XapmAssignString(apm, string, base)
  475. XAPM apm;
  476. Xchar *string;
  477. Xshort base;
  478. X{}
  479. X  This routine takes a character string containing the ASCII representation of
  480. X  a numeric value and converts it into a APM value in the base specified.  The
  481. X  'apm' parameter must have been previously initialized, 'string' must be
  482. X  non-NULL and valid in the specified base, and 'base' must be a valid base.
  483. X
  484. X  The return code and the 'apm_errno' variable reflect the status of this
  485. X  function.
  486. X
  487. Xint
  488. XapmConvert(string, length, decimals, round, leftjustify, apm)
  489. Xchar *string;
  490. Xint length;
  491. Xint decimals;
  492. Xint round;
  493. Xint leftjustify;
  494. XAPM apm;
  495. X{}
  496. X  This routine converts a APM value 'apm' into its ASCII representation
  497. X  'string'. The 'length' parameter is the maximum size of the string (including
  498. X  the trailing null), the 'decimals' parameter is the number of decimal places
  499. X  to display, the 'round' parameter is a true-false value which determines
  500. X  whether rounding is to take place (0 = false = no rounding), the
  501. X  'leftjustify' parameter is a true-false value which determines whether the
  502. X  result is to be left justified (0 = false = right justify; non-zero = true =
  503. X  left justify), and the 'apm' paramter is the APM value to be converted.
  504. X
  505. X  The 'string' parameter must point to an area that can hold at least 'length'
  506. X  bytes.
  507. X
  508. X  If the 'decimals' parameter is < 0, the string will contain the number of
  509. X  decimal places that are inherent in the APM value passed in.
  510. X
  511. X  The return code and the 'apm_errno' variable reflect the status of this
  512. X  function.
  513. X
  514. Xint
  515. X(*apmErrorFunc(newfunc))()
  516. Xint (*newfunc)();
  517. X{}
  518. X  This routine registers an error handler for errors and warnings.  Before any
  519. X  of the other APM routines return to the caller, an optional error handler
  520. X  specified in 'newfunc' can be called to intercept the result of the
  521. X  operation.  With a registered error handler, the caller can dispense with the
  522. X  repetitious code for checking 'apm_errno' or the function return status after
  523. X  each call to a APM routine.
  524. X
  525. X  If no error handler is registered or if 'newfunc' is set to NULL, no action
  526. X  will be taken on errors and warnings except to set the 'apm_errno' variable.
  527. X  If there is an error handler, it is called as follows when there is an error
  528. X  or a warning:
  529. X
  530. X      retcode = (*newfunc)(ercode, message, file, line, function)
  531. X
  532. X  where ...
  533. X
  534. X      int retcode;      /* returned by 'newfunc': should be 'ercode' */
  535. X      int ercode;       /* error code */
  536. X      char *message;    /* a short string describing the error */
  537. X      char *file;       /* the file in which the error occurred */
  538. X      int line;            /* the line on which the error occurred */
  539. X      char *function;    /* the name of the function in error */
  540. X
  541. X  Note that your error handler should normally return 'ercode' unless it does a
  542. X  longjmp, calls exit(), or in some other way interrupts the normal processing
  543. X  flow.  The value returned from your error handler is the value that the apm
  544. X  routine in error will return to its caller.
  545. X
  546. X  The error handler is called after 'apm_errno' is set.
  547. X
  548. X  This routine returns a pointer to the previously registered error handler or
  549. X  NULL if one isn't registered.
  550. X
  551. Xint
  552. XapmCalc(result, operand, ..., NULL)
  553. XAPM result;
  554. XAPM operand, ...;
  555. X{}
  556. X  This routine performs a series of calculations in an RPN ("Reverse
  557. X  Polish Notation") fashion, returning the final result in the 'result'
  558. X  variable.  It takes a variable number of arguments and hence the
  559. X  rightmost argument must be a NULL.
  560. X
  561. X  Each 'operand' is either a APM value or a special constant indicating
  562. X  the operation that is to be performed (see below).  This routine makes
  563. X  use of a stack (16 levels deep) similar to that in many pocket
  564. X  calculators.  It also is able to access a set of 16 auxiliary
  565. X  registers (numbered 0 through 15) for holding intermediate values.
  566. X
  567. X  The stack gets reinitialized at the start of this routine, so values
  568. X  that have been left on the stack from a previous call will disappear.
  569. X  However, the auxiliary registers are static and values remain in these
  570. X  registers for the duration of your program.  They may also be
  571. X  retrieved outside of this routine (see the apmGetRegister() and
  572. X  apmSetRegister() routines, below).
  573. X
  574. X  An operand that is an APM value is automatically pushed onto the stack
  575. X  simply by naming it in the function call.  If the stack is full when a
  576. X  value is being pushed onto it, the bottommost value drops off the
  577. X  stack and the push succeeds; this is similar to how many pocket
  578. X  calculators work.  Also, if the stack is empty, a pop will succeed,
  579. X  yielding a zero value and keeping the stack empty.  The topmost value
  580. X  on the stack is automatically popped into the 'result' parameter after
  581. X  all the operations have been performed.
  582. X
  583. X  An operand that is one of the following special values will cause
  584. X  an operation to be performed.  These operations are described in the
  585. X  following list.  Note that the values "V", "V1", and "V2" are used
  586. X  in the following list to stand for temporary values:
  587. X
  588. X    APM_ABS        pop V, push absolute value of V
  589. X    APM_NEG        pop V, push -V
  590. X    APM_CLEAR    empty the stack
  591. X    APM_DUP        pop V, push V, push V
  592. X    APM_SWAP    pop V1, pop V2, push V1, push V2
  593. X    APM_SCALE(N)    pop V, push V scaled by N [ as in apmScale() ]
  594. X    APM_PUSH(N)    V = value in register N, push V
  595. X    APM_POP(N)    pop V, store it in register N
  596. X    APM_ADD        pop V1, pop V2, push (V2 + V1)
  597. X    APM_SUB        pop V1, pop V2, push (V2 - V1)
  598. X    APM_MUL        pop V1, pop V2, push (V2 * V1)
  599. X    APM_DIV(N)    pop V1, pop V2, push (V2 / V1) with N radix places
  600. X            [ as in apmDivide() ], remainder goes into register 0
  601. X    APM_RECIP(N)    pop V, push 1/V with N radix places
  602. X            [ as in apmReciprocal() ]
  603. X
  604. X  Since register 0 is used to hold the remainder in a division, it is
  605. X  recommended that this register not be used to hold other values.
  606. X
  607. X  As an example, assume that APM values "foo", "bar", and "baz" have
  608. X  been initialized via apmInit() and that "foo" and "bar" are to be used
  609. X  to calculate "baz" as follows (assume that divisions stop after 16
  610. X  decimal places have been calcluated):
  611. X
  612. X    baz = 1 / ((((foo * bar) + foo) / bar) - foo)
  613. X
  614. X  The function call will be:
  615. X
  616. X    bcdCalc(baz, foo, APM_DUP, APM_POP(1), bar, APM_DUP, APM_POP(2),
  617. X        APM_MUL, APM_PUSH(1), APM_ADD, APM_PUSH(2), APM_DIV(16),
  618. X        APM_PUSH(1), APM_SUB, APM_RECIP(16), NULL);
  619. X
  620. X  Note that the value of "foo" is stored in register 1 and the value of
  621. X  "bar" is stored in register 2.  After this call, these registers will
  622. X  still contain those values.
  623. X
  624. Xint
  625. XapmGetRegister(regvalue, regnumber)
  626. XAPM regvalue;
  627. Xint regnumber;
  628. X{}
  629. X  The value in auxiliary register number 'regnumber' is assigned to APM
  630. X  value 'regvalue'.  The 'regnumber' parameter must be between 0 and 15,
  631. X  inclusive.  The 'regvalue' parameter must have been previously
  632. X  initialized via apmInit().
  633. X
  634. Xint
  635. XapmSetRegister(regvalue, regnumber, newvalue)
  636. XAPM regvalue;
  637. Xint regnumber;
  638. XAPM newvalue;
  639. X{}
  640. X  The value in auxiliary register number 'regnumber' is assigned to APM
  641. X  value 'regvalue', and then the APM value 'newvalue' is stored in that
  642. X  same register.  The 'regnumber' parameter must be between 0 and 15,
  643. X  inclusive.  The 'regvalue' and 'newvalue' parameters must have been
  644. X  previously initialized via apmInit().
  645. @\END_OF_FILE_FUNCTIONS
  646. else
  647.   echo "shar: Will not over write FUNCTIONS"
  648. fi
  649. echo "Finished archive 1 of 5"
  650. # to concatenate archives, remove anything after this line
  651. exit 0
  652.